package com.pat.jrgwt.client;

import java.util.Date;
import java.util.HashMap;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Grid;
import com.pat.jrgwt.shared.MyConstants;

public class DvRatio extends Composite
{

    private static DvRatioUiBinder uiBinder = GWT.create(DvRatioUiBinder.class);
    @UiField Grid DvRatioTotals;
    @UiField FlexTable DvRatioTable;
    protected HashMap<Integer, double[]> m_arRisks = new HashMap<Integer, double[]>();
    protected int m_totalYear = 8;
    @SuppressWarnings("deprecation")
    protected int m_currentYear = new Date().getYear();

    interface DvRatioUiBinder extends UiBinder<Widget, DvRatio>
    {
    }

    private DvRatio()
    {
        initWidget(uiBinder.createAndBindUi(this));
        formatDvRatio();
//        loadData();
//        redrawData();
    }
    
    private static class SingletonHolder
    {
        private static final DvRatio instance = new DvRatio();
    }
    
    public static DvRatio getInstance()
    {
        return SingletonHolder.instance;
    }
    
    public void recalculate()
    {
        int row = 1;
        double risk = 0;
        double perf = 0;
        double perfLev = 0;
        double riskPerMonth = 0;
        double additionalPerf = 0;
        double downsideVolaCalculation = 0;
        
        double varAdditionalPerf = 0;
        double varPerformance = 0;
        
        double initialPerf = 5;
        NumberFormat nf = NumberFormat.getFormat("###,##0.00");
        NumberFormat nf3 = NumberFormat.getFormat("###,##0.000");
        
        DvRatioStats stats = new DvRatioStats();
        
        // Get data from ArchivePerf
        ArchivePerf archivePerv = ArchivePerf.getInstance();
        
        for (int i = 0; i < m_totalYear; i++)
        {
            int year = 1900 + m_currentYear - m_totalYear + i;
            DvRatioTable.setText(row, 0, "" + year);
            for (int month = 1; month < 13; month++)
            {
                DvRatioTable.setText(row, 1, "" + month);
                
//                GWT.log("Getting risk for " + year + "-" + month);
                risk = getRiskByDate(year, month);
//                GWT.log("Risk is: " + risk);
                if( risk != Double.MIN_VALUE )
                {
//                    GWT.log("Getting archive performance for: " + year + "-" + month);
                    perf = archivePerv.getPerfByDate(year, month);
                    if( perf != Double.MIN_VALUE )
                    {
                        perfLev = initialPerf * perf;
                    }else
                    {
                        perfLev = 0;
                    }

                    riskPerMonth = risk / 12;
                    additionalPerf = perfLev - riskPerMonth;
                    downsideVolaCalculation = additionalPerf < 0 ? additionalPerf * additionalPerf : 0;
                    
                    DvRatioTable.setText(row, 2, nf.format(perfLev));
                    DvRatioTable.setText(row, 3, nf3.format(risk));
                    DvRatioTable.setText(row, 4, nf3.format(riskPerMonth));
                    DvRatioTable.setText(row, 5, nf3.format(additionalPerf));
                    DvRatioTable.setText(row, 8, nf3.format(downsideVolaCalculation));
                    
                    // Calculate statistics
                    stats.totalAdditionalPerf += additionalPerf;
                    stats.totalMonthlyReturn += perfLev;
                    stats.totalDownsideVolatility += downsideVolaCalculation;
                    stats.totalRiskPerMonth += riskPerMonth;
                    
                    if( stats.maxMonthlyReturn < perfLev )
                    {
                        stats.maxMonthlyReturn = perfLev;
                    }
                    if( stats.minMonthlyReturn > perfLev )
                    {
                        stats.minMonthlyReturn = perfLev;
                    }
                    stats.totalRecords++;
                    
                }else  // END IF ( risk is not undefined )
                {
                    for (int j = 2; j < DvRatioTable.getCellCount(0); j++)
                    {
                        DvRatioTable.setText(row, j, "");
                    }
                }
                
                row++;
            }
        }  // END FOR ( years )
        
//        stats.averageMonthlyReturn = stats.totalMonthlyReturn / stats.totalRecords;
//        stats.averageRiskPerMonth = stats.totalRiskPerMonth / stats.totalRecords;
//        stats.averageAdditionalPerf = stats.totalAdditionalPerf / stats.totalRecords;
//        stats.averageDownsideVolatility = stats.totalDownsideVolatility / stats.totalRecords;
        
//        int pos = 0;
//        for(int i = 0; i < m_totalYear; i++)
//        {
//            int year = 1900 + m_currentYear - m_totalYear + i;
//            for (int month = 1; month < 13; month++)
//            {
//                varAdditionalPerf = stats.averageAdditionalPerf;
//                DvRatioTable.setText(pos, 6, nf3.format(varAdditionalPerf));
//                pos++;
//            }
//            
//        }
        
        // Display averages
        DvRatioTable.setText(row, 1, "Averages");
        DvRatioTable.setText(row, 2, nf3.format(stats.getAverageMonthlyReturn()));
        DvRatioTable.setText(row, 4, nf3.format(stats.getAverageRiskPerMonth()));
        DvRatioTable.setText(row, 5, nf3.format(stats.getAverageAdditionalPerf()));
        DvRatioTable.setText(row, 8, nf3.format(stats.getAverageDownsideVolatility()));
        
        row += 10;
        DvRatioTable.setText(row, 7, nf3.format(stats.maxMonthlyReturn));
        row++;
        DvRatioTable.setText(row, 7, nf3.format(stats.minMonthlyReturn));
    }

    protected double getRiskByDate(int year, int month)
    {
        double value = Double.MIN_VALUE;
        
        if( m_arRisks.containsKey(year) )
        {
            if( (month > 0) && (month < 13) )
            {
                value = m_arRisks.get(year)[month - 1];
            }
        }
        
        return value;
    }
    
    public void setData(HashMap<Integer, double[]> arRisks)
    {
        m_arRisks = arRisks;
    }
    
//    protected void loadData()
//    {
//        JsonRequest.get(MyConstants.EXCHANGE_SERVER_URL + "pet/getdvratio?callback=", new JsonRequestHandler()
//        {
//            
//            @Override
//            public void onRequestCompleted(JavaScriptObject json)
//            {
//                JrcEventsLog.getInstance().add("Got JSON data for DvRatio...");
//                if( json != null )
//                {
//                    m_arRisks = DvRatio.parseJsonData(json);
//                    recalculateData();
//                }
//            }
//        });
////        m_arRisks.put(2004, new double[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 });
//        
//    }

    /**
     * Parses JSON data from server and return HashMap
     * @param json
     * @return
     */
    public static HashMap<Integer, double[]> parseJsonData(JavaScriptObject json)
    {
        JSONObject jsonObj = new JSONObject(json);
        HashMap<Integer, double[]> arRisks = new HashMap<Integer, double[]>();
        try
        {
            int year = 0;
            double[] values = null;
            GWT.log("Parsing JSON data for DV ratio...");
            for( String key : jsonObj.keySet() )
            {
                year = Integer.parseInt(key);
                values = new double[12];
                JSONArray ar = jsonObj.get(key).isArray();
                for(int month = 0; month < ar.size(); month++)
                {
                    values[month] = Double.parseDouble(ar.get(month).toString().replaceAll("\"", ""));
                }
                arRisks.put(year, values);
            }
            GWT.log("DV ratio JSON parsing is finished");
        }
        catch( Exception e )
        {
            GWT.log("Error parsing DV ratio JSON from ITTC server! " + e.toString());
        }
        
        return arRisks;
    }

    
    public void formatDvRatio()
    {
        DvRatioTable.setBorderWidth(1);
        
        String[] arHeaders = new String[] { "Year", "Month", "Performance (levered, %)", "risk free interest (%)", "risk free interest per month (%)", "Additional performance (%)", "VAR (additional performance)", "VAR (Performance)", "Downside Vola. Calculation" };
        for (int i = 0; i < arHeaders.length; i++)
        {
            DvRatioTable.setText(0, i, arHeaders[i]);
            DvRatioTable.getCellFormatter().setStylePrimaryName(0, i, "cellBold");
        }
    }

}
